package com.sky.service.impl;

import com.sky.dto.GoodsSalesDTO;
import com.sky.entity.Orders;
import com.sky.entity.User;
import com.sky.mapper.OrderDetailMapper;
import com.sky.mapper.OrdersMapper;
import com.sky.mapper.UserMapper;
import com.sky.service.ReportService;
import com.sky.service.WorkspaceService;
import com.sky.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 报表管理
 */
@Slf4j
@Service
public class ReportServiceImpl implements ReportService {

    public static final String REPORT_TEMPLATE_XLSX = "template/business_data_report_template.xlsx";

    @Autowired
    private OrdersMapper ordersMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private WorkspaceService workspaceService;

    @Override
    public TurnoverReportVO turnoverStatistics(LocalDate beginDate, LocalDate endDate) {
        // 1. 计算日期列表
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        List<String> dateList = new ArrayList<>();
        dateList.add(dateTimeFormatter.format(beginDate));
        for (LocalDate date = beginDate; !date.isAfter(endDate); date = date.plusDays(1)) {
            dateList.add(dateTimeFormatter.format(date));
        }
        String dateListStr = StringUtils.join(dateList, ",");

        // 2. 查询指定日期范围内的已完成的订单数据
        LocalDateTime beginTime = LocalDateTime.of(beginDate, LocalDateTime.MIN.toLocalTime());
        LocalDateTime endTime = LocalDateTime.of(endDate.plusDays(1), LocalDateTime.MIN.toLocalTime());
        List<Orders> orders = ordersMapper.getOrdersByDateRange(beginTime, endTime, Orders.COMPLETED);
        // 按照日期分组
        Map<String, List<Orders>> dateOrdersMap = orders.stream()
                .collect(Collectors.groupingBy(order -> dateTimeFormatter.format(order.getOrderTime())));

        // 3. 计算每日的营业额
        List<BigDecimal> turnoverList = new ArrayList<>(dateList.size());
        for (String date : dateList) {
            List<Orders> ordersForDate = dateOrdersMap.get(date);
            if (CollectionUtils.isEmpty(ordersForDate)) {
                turnoverList.add(BigDecimal.ZERO);
                continue;
            }
            BigDecimal totalTurnover = ordersForDate.stream()
                    .map(Orders::getAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            turnoverList.add(totalTurnover);
        }
        // 将营业额列表转换为字符串
        String turnoverListStr = StringUtils.join(turnoverList, ",");

        // 4. 返回结果
        return TurnoverReportVO.builder()
                .dateList(dateListStr)
                .turnoverList(turnoverListStr)
                .build();
    }

    @Override
    public UserReportVO userStatistics(LocalDate beginDate, LocalDate endDate) {
        LocalDateTime beginTime = LocalDateTime.of(beginDate, LocalDateTime.MIN.toLocalTime());
        LocalDateTime endTime = LocalDateTime.of(endDate.plusDays(1), LocalDateTime.MIN.toLocalTime());

        // 1. 计算日期列表
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        List<String> dateList = new ArrayList<>();
        dateList.add(dateTimeFormatter.format(beginDate));
        for (LocalDate date = beginDate; !date.isAfter(endDate); date = date.plusDays(1)) {
            dateList.add(dateTimeFormatter.format(date));
        }
        String dateListStr = StringUtils.join(dateList, ",");

        // 2. 查询指定日期范围内的新增用户数量
        List<User> users = userMapper.getUserByDateRange(beginTime, endTime);
        Map<String, List<User>> dateUserMap = users.stream()
                .collect(Collectors.groupingBy(user -> dateTimeFormatter.format(user.getCreateTime())));
        List<Integer> newUserList = new ArrayList<>(dateList.size());
        for (String date : dateList) {
            List<User> usersForDate = dateUserMap.get(date);
            if (CollectionUtils.isEmpty(usersForDate)) {
                newUserList.add(0);
                continue;
            }
            int newUserCount = usersForDate.size();
            newUserList.add(newUserCount);
        }
        String newUserListStr = StringUtils.join(newUserList, ",");

        // 3. 计算每日的用户总量
        List<Integer> totalUserList = new ArrayList<>(dateList.size());
        int totalUserCount = userMapper.getUserCountByDateRange(null, beginTime);
        for (Integer newUserCount : newUserList) {
            totalUserCount += newUserCount;
            totalUserList.add(totalUserCount);
        }
        String totalUserListStr = StringUtils.join(totalUserList, ",");

        // 4. 返回结果
        return UserReportVO.builder()
                .dateList(dateListStr)
                .totalUserList(totalUserListStr)
                .newUserList(newUserListStr)
                .build();
    }

    @Override
    public OrderReportVO ordersStatistics(LocalDate beginDate, LocalDate endDate) {
        // 1. 计算日期列表
        List<LocalDate> dateList = new ArrayList<>();
        dateList.add(beginDate);
        for (LocalDate date = beginDate; !date.isAfter(endDate); date = date.plusDays(1)) {
            dateList.add(date);
        }
        String dateListStr = StringUtils.join(dateList, ",");

        // 2. 查询指定日期范围内的订单数量
        List<Integer> orderCountList = new ArrayList<>(dateList.size());
        List<Integer> validOrderCountList = new ArrayList<>(dateList.size());
        for (LocalDate date : dateList) {
            LocalDateTime beginTime = LocalDateTime.of(date, LocalDateTime.MIN.toLocalTime());
            LocalDateTime endTime = LocalDateTime.of(date.plusDays(1), LocalDateTime.MIN.toLocalTime());
            int orderCount = ordersMapper.countByDateRange(beginTime, endTime, null);
            int validOrderCount = ordersMapper.countByDateRange(beginTime, endTime, Orders.COMPLETED);
            orderCountList.add(orderCount);
            validOrderCountList.add(validOrderCount);
        }

        // 3. 计算订单完成率
        int totalOrderCount = orderCountList.stream()
                .mapToInt(Integer::intValue)
                .sum();
        int validOrderCount = validOrderCountList.stream()
                .mapToInt(Integer::intValue)
                .sum();
        double orderCompletionRate = totalOrderCount == 0 ? 0 : (double) validOrderCount / totalOrderCount;

        // 4. 返回结果
        return OrderReportVO.builder()
                .dateList(dateListStr)
                .orderCountList(StringUtils.join(orderCountList, ","))
                .validOrderCountList(StringUtils.join(validOrderCountList, ","))
                .totalOrderCount(totalOrderCount)
                .validOrderCount(validOrderCount)
                .orderCompletionRate(orderCompletionRate)
                .build();
    }

    @Override
    public SalesTop10ReportVO salesTop10(LocalDate beginDate, LocalDate endDate) {
        // 1. 转换日期格式
        LocalDateTime beginTime = LocalDateTime.of(beginDate, LocalDateTime.MIN.toLocalTime());
        LocalDateTime endTime = LocalDateTime.of(endDate.plusDays(1), LocalDateTime.MIN.toLocalTime());

        // 2. 查询前10的商品及其销售量
        List<GoodsSalesDTO> goodsSalesDTOList = orderDetailMapper.getTop10SalesGood(beginTime, endTime);

        // 3. 构建结果对象
        String nameList = goodsSalesDTOList.stream()
                .map(GoodsSalesDTO::getName)
                .collect(Collectors.joining(","));
        String numberList = goodsSalesDTOList.stream().map(GoodsSalesDTO::getNumber)
                .map(String::valueOf)
                .collect(Collectors.joining(","));

        // 4. 返回结果
        return SalesTop10ReportVO.builder()
                .nameList(nameList)
                .numberList(numberList)
                .build();
    }

    @Override
    public void export(HttpServletResponse response) throws Exception {
        // 1. 打开模板文件
        try (InputStream in = getClass().getClassLoader().getResourceAsStream(REPORT_TEMPLATE_XLSX);
             XSSFWorkbook excel = new XSSFWorkbook(in)) {
            XSSFSheet sheet = excel.getSheetAt(0);

            // 2. 计算导出数据的日期范围
            LocalDate beginDate = LocalDate.now().minusDays(30);
            LocalDate endDate = LocalDate.now().minusDays(1);
            LocalDateTime beginTime = LocalDateTime.of(beginDate, LocalDateTime.MIN.toLocalTime());
            LocalDateTime endTime = LocalDateTime.of(endDate.plusDays(1), LocalDateTime.MIN.toLocalTime());
            String dateRange = "时间：" + beginDate + " - " + endDate;
            sheet.getRow(1).getCell(1).setCellValue(dateRange);

            // 3. 查询概览数据
            BusinessDataVO businessData = workspaceService.getBusinessData(beginTime, endTime);
            XSSFRow row3 = sheet.getRow(3);
            row3.getCell(2).setCellValue(businessData.getTurnover());
            row3.getCell(4).setCellValue(businessData.getOrderCompletionRate());
            row3.getCell(6).setCellValue(businessData.getNewUsers());
            XSSFRow row4 = sheet.getRow(4);
            row4.getCell(2).setCellValue(businessData.getValidOrderCount());
            row4.getCell(4).setCellValue(businessData.getUnitPrice());

            // 4. 查询每天订单明细数据
            for (int i = 0; i < 30; i++) {
                // 查询当天数据
                LocalDateTime dateTime = beginTime.plusDays(i);
                BusinessDataVO data = workspaceService.getBusinessData(dateTime, dateTime.plusDays(1));
                // 填充数据
                XSSFRow row = sheet.getRow(7 + i);
                row.getCell(1).setCellValue(dateTime.toLocalDate().toString());
                row.getCell(2).setCellValue(data.getTurnover());
                row.getCell(3).setCellValue(data.getValidOrderCount());
                row.getCell(4).setCellValue(data.getOrderCompletionRate());
                row.getCell(5).setCellValue(data.getUnitPrice());
                row.getCell(6).setCellValue(data.getNewUsers());
            }

            // 6. 导出文件
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-Disposition", "attachment; filename=report.xlsx");
            excel.write(response.getOutputStream());
        } catch (Exception e) {
            log.error("导出报表失败", e);
            throw new RuntimeException("导出报表失败");
        }
    }

}
